#########################
#
# 特么的各厂商都不完全遵循 OAuth2.0 协议，异同点参照这里：
# http://blog.yorkxin.org/posts/2013/09/30/oauth2-implementation-differences-among-famous-sites
#
#########################

class OauthBase
  include OauthModule

  SETTINGS = AppSettings.oauth

  delegate :url_helpers, to: 'Rails.application.routes'

  attr_reader :key, :secret, :callback_uri
  attr_accessor :code, :scope_delimiter, :method, :grant_type

  def initialize(options = {})
    @key, @secret, @callback_uri = settings
    @method = 'post'        # 请求方法
    @scope = scope          # 授权范围
    @scope_delimiter = ','  # scope 分隔符
    @options = options      # 其他非通用选项
    @response_type = 'code'
    @grant_type = 'authorization_code'
  end

  def authorize
    query = {client_id: @key, response_type: @response_type,
             redirect_uri: @callback_uri, scope: scope.join(@scope_delimiter)}
    query.merge! @options[:authorize_params] if @options[:authorize_params]
    "#{authorize_url}?#{CGI.unescape(query.to_query)}"
  end

  def access_client(net: false, token: false)
    if token
      OauthClient.new token
    elsif net
      OauthClient.new ''
    else
      client = get_access_token
      begin
        store_user_info client
      rescue Exception => e
        rescue_from e
      end
      client
    end
  end

  def access_token
    client = get_access_token
    begin
      store_user_info client
    rescue Exception => e
      rescue_from e
    end
    client.access_token
  end

  def return_url_after_auth
    @specify_url || url_helpers.oauth_bind_url(host: AppSettings.host)
  end

  protected
  def settings
    info = SETTINGS.send self.class.name.demodulize.underscore
    [info.key, info.secret, info.callback_uri]
  end

  def get_access_token
    params = {client_id: @key, client_secret: @secret, code: code,
              grant_type: @grant_type, redirect_uri: @callback_uri}
    params.merge! @options[:access_params] if @options[:access_params]
    begin
      method = @method.downcase
      response = if method == 'get'
                   RestClient.send(method, access_url, params: params)
                 else
                   RestClient.send(method, access_url, params)
                 end
      klient.new response
    rescue Exception => e
      rescue_from e, response: response
    end
  end

  # 授权范围
  def scope; []; end

  # 存储用户信息
  def store_user_info(client); end

  # 处理错误
  def rescue_from(exception, response: '{}'); raise exception; end

  # 可定制 oauth client,适配恶心的豆瓣
  def klient; OauthClient; end

  # 检查 uid 是否存在，true 表示存在
  def check_uid(uid)

    false
  end
end